package com.yunshipei.core.manager;

import android.content.Context;
import android.os.Environment;
import android.text.TextUtils;

import com.yunshipei.core.common.Callback;
import com.yunshipei.core.common.XCloudException;
import com.yunshipei.core.model.ConfigInfo;
import com.yunshipei.core.net.EnterClient;
import com.yunshipei.core.net.ServiceApi;
import com.yunshipei.core.net.convert.JsonConverterFactory;
import com.yunshipei.core.utils.SystemUtils;

import org.json.JSONException;
import org.json.JSONObject;
import org.reactivestreams.Publisher;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;


public final class LogManager {

    private static final String LOG_FILE_NAME = "dynamic.log";
    private static final String LOG_ROOT_PATH = Environment.getExternalStorageDirectory().getPath() + File.separator + "com.ysp.xcloud" + File.separator + "log";

    //日志状态，0: 开始，1: 结束，3: 单一日志
    public static final int STATUS_START = 0;
    public static final int STATUS_END = 1;

    private static final ExecutorService SINGLE_THREAD_EXECUTOR = Executors.newSingleThreadExecutor();
    private static final Object object = new Object();
    private Map<String, String> mBaseInfo = new HashMap<>();

    private LogManager() {
    }

    private static final class EnterLogManagerInner {
        private static final LogManager instance = new LogManager();
    }

    public static LogManager getInstance() {
        return EnterLogManagerInner.instance;
    }

    //日志初始化
    public void init(Context context) {
        String sessionID = System.currentTimeMillis() + "";
        String device = SystemUtils.getDevicesName();
        String appVersion = SystemUtils.getVersionName(context);
        String platform = SystemUtils.getPlatform(context);
        String osVersion = SystemUtils.getSystemVersion();
        mBaseInfo.put("sessionID", sessionID);
        mBaseInfo.put("device", device);
        mBaseInfo.put("version", appVersion);
        mBaseInfo.put("platform", platform);
        mBaseInfo.put("OSVersion", osVersion);
        mBaseInfo.put("OS", "Android");
    }

    //保存适配传过来的日志
    public void saveAdapterLog(final String log) {
        SINGLE_THREAD_EXECUTOR.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    writeLog(new JSONObject(log));
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    //app保存日志
    public void saveNativeLog(String level, String action, JSONObject content, int status, String scope, String rtVersion) {
        try {
            final JSONObject jsonObject = new JSONObject();
            jsonObject.put("time", SystemUtils.getISOTimeFormat());
            jsonObject.put("level", level);
            jsonObject.put("action", action);
            jsonObject.put("RTVersion", rtVersion);
            jsonObject.put("scope", scope);
            jsonObject.put("role", "Android");
            jsonObject.put("content", content);
            jsonObject.put("status", status);
            SINGLE_THREAD_EXECUTOR.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        writeLog(jsonObject);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //保存在SD卡上的日志
    public void saveDebugLog(final String log) {
        SINGLE_THREAD_EXECUTOR.execute(new Runnable() {
            @Override
            public void run() {
                String rootPath = makeLogPath();
                if (!TextUtils.isEmpty(rootPath)) {
                    SimpleDateFormat fileNameFormatter = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
                    Date curDate = new Date(System.currentTimeMillis());//获取当前时间
                    String fileName = fileNameFormatter.format(curDate) + ".log";
                    File file = new File(rootPath, fileName);
                    boolean exists = file.exists();
                    FileWriter fileWriter = null;
                    try {
                        fileWriter = new FileWriter(file, true);
                        if (!exists) {
                            fileWriter.write(appendBaseInfo(new JSONObject()) + System.getProperty("line.separator"));
                        }
                        SimpleDateFormat formatter = new SimpleDateFormat("[HH:mm:ss:SSS] ", Locale.getDefault());
                        String time = formatter.format(curDate);
                        String temp = time + log + System.getProperty("line.separator");
                        fileWriter.write(temp);
                        fileWriter.flush();
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        if (fileWriter != null) {
                            try {
                                fileWriter.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        });
    }

    private JSONObject appendBaseInfo(JSONObject jsonObject) throws JSONException {
        Set<Map.Entry<String, String>> entrySet = mBaseInfo.entrySet();
        for (Map.Entry<String, String> entry : entrySet) {
            String key = entry.getKey();
            String value = entry.getValue();
            jsonObject.put(key, value);
        }
        return jsonObject;
    }

    private ServiceApi mServiceApi;

    /**
     * 发送日志到manager服务器
     */
    public void sendLog(String fileName, final Callback callback) {
        synchronized (object) {
            final File logFile = new File(LOG_ROOT_PATH, LOG_FILE_NAME);
            if (logFile.exists()) {
                if (mServiceApi == null) {
                    ConfigInfo configInfo = XCloud2Map.getInstance().getConfigInfo();
                    if (configInfo == null) {
                        if (callback != null) {
                            callback.error("适配数据未初始化...");
                        }
                        return;
                    }
                    mServiceApi = new Retrofit.Builder().client(EnterClient.getInstances().getManagerClient()).baseUrl(configInfo.getUrl()).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).addConverterFactory(JsonConverterFactory.create()).build().create(ServiceApi.class);
                }
                RequestBody fileBody = RequestBody.create(MediaType.parse("*/*"), logFile);
                Map<String, RequestBody> map = new HashMap<>();
                map.put("file\"; filename=\"" + fileName + "\"", fileBody);
                mServiceApi.uploadLogFile(map).flatMap(new Function<JSONObject, Publisher<Boolean>>() {
                    @Override
                    public Publisher<Boolean> apply(JSONObject jsonObject) throws Exception {
                        if (1 == jsonObject.optInt("status", 0)) {
                            boolean b = logFile.delete();
                            return Flowable.just(true);
                        }
                        return Flowable.error(new XCloudException(jsonObject.optString("message", "日志上传失败，未知异常...")));
                    }
                }).subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Boolean>() {
                    @Override
                    public void accept(Boolean aBoolean) throws Exception {
                        if (callback != null) {
                            callback.success();
                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        if (callback != null) {
                            callback.error(throwable.toString());
                        }
                    }
                });
            } else {
                if (callback != null) {
                    callback.error("没有可上传日志");
                }
            }
        }
    }

    //创建日志保存路径
    private String makeLogPath() {
        if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
            File rootFile = new File(LOG_ROOT_PATH);
            if (rootFile.exists() || rootFile.mkdirs()) {
                return LOG_ROOT_PATH;
            }
        }
        return "";
    }

    private void writeLog(JSONObject jsonObject) throws JSONException {
        JSONObject result = appendBaseInfo(jsonObject);
        String finalLog = result.toString() + ",";
        String path = makeLogPath();
        if (!TextUtils.isEmpty(path)) {
            File file = new File(path, LOG_FILE_NAME);
            FileWriter fileWriter = null;
            try {
                fileWriter = new FileWriter(file, true);
                fileWriter.write(finalLog);
                fileWriter.flush();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fileWriter != null) {
                    try {
                        fileWriter.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
